import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import mnist         # библиотека базы выборок Mnist
from tensorflow import keras
from tensorflow.keras.layers import Dense, Flatten, Dropout, Conv2D, MaxPooling2D

# Загрузка базы данных MNIST
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# Стандартизация входных данных путем деления на 255, чтобы значения были в диапазоне от 0 до 1
x_train = x_train / 255
x_test = x_test / 255

# Преобразование меток классов в формат one-hot encoding
y_train_cat = keras.utils.to_categorical(y_train, 10)
y_test_cat = keras.utils.to_categorical(y_test, 10)

# Расширение размерности входных изображений для соответствия требованиям сверточных слоев
x_train = np.expand_dims(x_train, axis=3)
x_test = np.expand_dims(x_test, axis=3)

print(x_train.shape)

# Создание модели с архитектурой сверточной нейронной сети
model = keras.Sequential([
    Conv2D(32, (3,3), padding='same', activation='relu', input_shape=(28, 28, 1)),
    MaxPooling2D((2, 2), strides=2),
    Conv2D(64, (3,3), padding='same', activation='relu'),
    MaxPooling2D((2, 2), strides=2),
    Flatten(),
    Dense(128, activation='relu'),
    Dense(10,  activation='softmax')
])

# Компиляция модели с оптимизатором Adam, функцией потерь categorical_crossentropy и метрикой точности
model.compile(optimizer='adam',
             loss='categorical_crossentropy',
             metrics=['accuracy'])

# Обучение модели на обучающих данных с размером пакета 32, на протяжении 5 эпох,
# с использованием 20% обучающих данных в качестве валидационной выборки
his = model.fit(x_train, y_train_cat, batch_size=32, epochs=5, validation_split=0.2)

# Оценка производительности модели на тестовых данных
model.evaluate(x_test, y_test_cat)

# Оценка производительности модели на тестовых данных
loss, accuracy = model.evaluate(x_test, y_test_cat)
print('Потеря на тестовых данных:', loss)
print('Точность на тестовых данных:', accuracy)

# Выбор случайного изображения из тестовой выборки
index = np.random.randint(0, len(x_test))
image = x_test[index]
label = y_test[index]

# Получение предсказания модели для выбранного изображения
prediction = model.predict(np.expand_dims(image, axis=0))
predicted_label = np.argmax(prediction)

# Визуализация выбранного изображения и предсказанного класса
plt.imshow(image.squeeze(), cmap='gray')
plt.title(f'Предсказанная метка: {predicted_label}, Истинная метка: {label}')
plt.axis('off')
plt.show()

